//-------------------------------------------------------------
// \project PluginExample3
// \file ModuleCorrect.java
// \brief 气候资料订正->条件温差订正模块
// \author 王庆飞
// \date 2017-10-16
// \attention
// Copyright(c) 超图软件股份有限公司 气象事业部
// All Rights Reserved
// \version 1.0
//-------------------------------------------------------------

package com.mg.pluginexample3;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.LinkedList;
import java.util.List;

import com.mg.model.*;
import com.mg.pluginexample1.*;

public class ModuleCorrect extends Module 
{
	public ModuleCorrect(int nID) 
	{
		super(nID);
		
		m_alInputPort.add(new DataTablePort(this, Port.Type.CSV));
		m_alInputPort.add(new DataTablePort(this, Port.Type.CSV));
		m_alInputPort.add(new DataTablePort(this, Port.Type.CSV));
		
		m_alInputPort.get(0).SetName("例如：基本站1981-2016 月(旬)平均气温");
		m_alInputPort.get(1).SetName("例如：基本站2008-2016 日平均气温,日平均总云量");
		m_alInputPort.get(2).SetName("例如：考察站2008-2016 日平均气温");
		
		m_alOutputPort.add(new Port(this, Port.Type.CSV));
		m_alOutputPort.get(0).SetName("例如：考察站各月(旬)多年(1981-2016)平均气温");
    }

	public String GetGroupName()
	{
		return "JDBC";
	}
	public String GetName()
	{
		return "条件温差\n订正";
	}
	public String GetDescription()
	{
		return "用于订正气温。";
	}
	
	public boolean OnAttach(Port portFrom, Port portTo)
	{
		try
		{
			int i = FindPort(portFrom, false);
			if (i != -1)
				return true;
			i = FindPort(portTo, true);
			if (i == -1)
				return false;
			
			ArrayList<Param> alParam = new ArrayList<Param>();
			portFrom.GetModule().GetOutputParam(portFrom, alParam);
			if (alParam.size() != 1)
				return false;
			if (alParam.get(0).m_objValue != null && !(alParam.get(0).m_objValue instanceof List<?>))
				return false;
			portTo.SetType(portFrom.GetType());
			DataTablePort dtp = (DataTablePort)portTo;
			if (alParam.get(0).m_objValue instanceof List<?>)
				dtp.m_list = (List<String>)alParam.get(0).m_objValue;
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
			return false;
		}
		return true;
	}
	
	//用于 参数->XML 等
	public int GetParam(ArrayList<Param> alParam)
	{
		try
		{
			int nOffset = super.GetParam(alParam);
			//-------------------------------------------------------------------------------------------------------------------
		
        	
			Model.GetAlias(alParam, m_alAlias, nOffset);
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
		}
		
		return alParam.size();
	}
	//用于 XML->参数 等
	public int SetParam(final ArrayList<Param> alParam)
	{
		int i = super.SetParam(alParam);
		
		try
		{
			
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
		}
		return i;	
	}
	
	public boolean Execute()
	{
		try
		{
			int i = 0, j = 0, k = 0;
			
			DataTablePort dtp = (DataTablePort)m_alInputPort.get(0);
			boolean bTenDays = dtp.m_list.get(0).contains("旬");
			
			SimpleDateFormat sdf = new SimpleDateFormat(bTenDays ? "yyyy-MM-dd" : "yyyy-MM");
			m_alBMonthData.clear();
			for (i = 2; i < dtp.m_list.size(); i++)
        	{
				String[] strs = dtp.m_list.get(i).split(",");
        		m_alBMonthData.add(new BMonthData(sdf.parse(strs[0]), Double.parseDouble(strs[1])));
        	}
			
			dtp = (DataTablePort)m_alInputPort.get(1);
			sdf = new SimpleDateFormat("yyyy-MM-dd");
			m_alBDayData.clear();
			for (i = 2; i < dtp.m_list.size(); i++)
        	{
				String[] strs = dtp.m_list.get(i).split(",");
        		m_alBDayData.add(new BDayData(sdf.parse(strs[0]), Double.parseDouble(strs[1]), Double.parseDouble(strs[2])));
        	}
			
			dtp = (DataTablePort)m_alInputPort.get(2);
			m_alADayData.clear();
			for (i = 2; i < dtp.m_list.size(); i++)
        	{
				String[] strs = dtp.m_list.get(i).split(",");
        		m_alADayData.add(new ADayData(sdf.parse(strs[0]), Double.parseDouble(strs[1])));
        	}
			if (m_alBDayData.size() != m_alADayData.size())
			{
				m_model.OutputLog(Model.LogLevel.Error, String.format("\"%s-%d\"模块\"基本站日数和考察站日数不相等。", GetNestedName(), GetID()));
				return false;
			}
			//-------------------------------------------------------------------------------------------------------------------
			//统计基本站各月多年平均气温
			double[] tb = new double[bTenDays ? 36 : 12];
			int[] count = new int[bTenDays ? 36 : 12];
			for (i = 0; i < tb.length; i++)
			{
				tb[i] = 0.0;
				count[i] = 0;
			}
			for (i = 0; i < m_alBMonthData.size(); i++)
			{
				BMonthData bmd = m_alBMonthData.get(i);
				Calendar c = new GregorianCalendar();
				c.setTime(bmd.m_dateTime);
				if (bTenDays)
				{
					final int nDayOfMonth = c.get(Calendar.DAY_OF_MONTH);
					j = c.get(Calendar.MONTH) * 3 + (nDayOfMonth < 11 ? 0 : (nDayOfMonth < 21 ? 1 : 2));
				}
				else
				{
					j = c.get(Calendar.MONTH);
				}
				tb[j] += bmd.m_t;
				++count[j];
			}
			for (i = 0; i < tb.length; i++)
			{
				if (count[i] != 0)
					tb[i] /= count[i];
			}
			//-------------------------------------------------------------------------------------------------------------------
			double[][] delta_t = new double[bTenDays ? 36 : 12][3]; //晴、云、阴天条件下的温差
			int[][] p = new int[bTenDays ? 36 : 12][3]; //晴、云、阴天数
			for (i = 0; i < (bTenDays ? 36 : 12); i++)
			{
				for (j = 0; j < 3; j++)
				{
					delta_t[i][j] = 0.0;
					p[i][j] = 0;
				}
			}
			for (i = 0; i < m_alBDayData.size(); i++)
			{
				if (Math.abs(m_alADayData.get(i).m_t - 999.9) < 1e-10) //无效值
					continue;
				BDayData bdd = m_alBDayData.get(i);
				Calendar c = new GregorianCalendar();
				c.setTime(bdd.m_dateTime);
				if (bTenDays)
				{
					final int nDayOfMonth = c.get(Calendar.DAY_OF_MONTH);
					j = c.get(Calendar.MONTH) * 3 + (nDayOfMonth < 11 ? 0 : (nDayOfMonth < 21 ? 1 : 2));
				}
				else
				{
					j = c.get(Calendar.MONTH);
				}
				k = (bdd.m_c < 20 ? 0 : (bdd.m_c > 80 ? 2 : 1));
				delta_t[j][k] += (m_alADayData.get(i).m_t - bdd.m_t);
				++p[j][k];
			}
			for (i = 0; i < (bTenDays ? 36 : 12); i++)
			{
				for (j = 0; j < 3; j++)
				{
					if (p[i][j] != 0)
						delta_t[i][j] /= p[i][j];
				}
			}
			//-------------------------------------------------------------------------------------------------------------------
			double[] ta = new double[bTenDays ? 36 : 12];
			for (i = 0; i < (bTenDays ? 36 : 12); i++)
			{
				ta[i] = tb[i] + (delta_t[i][0] * p[i][0] + delta_t[i][1] * p[i][1] + delta_t[i][2] * p[i][2]) / (p[i][0] + p[i][1] + p[i][2]); 
			}
			//-------------------------------------------------------------------------------------------------------------------
			m_llOutput.clear();
			m_llOutput.add((bTenDays ? "旬" : "月") + ",多年平均气温");
			m_llOutput.add("TINYINT,FLOAT");
			for (i = 0; i < ta.length; i++)
			{
				m_llOutput.add(String.format("%d,%f", i + 1, ta[i])); 
			}
			
			OnParamChanged();
			return true;
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
		}
		catch (Error error)
		{
			error.printStackTrace();
		}
		
		return false;
	}
	
	public int GetOutputParam(Port port, ArrayList<Param> alParam)
	{
		int i = FindPort(port, false);
		if (i == -1)
			return 0;
		if (i == 0)
			alParam.add(new Param("CSV", m_llOutput));
		
		return alParam.size();
	}
	//---------------------------------------------------------------------------
	class BMonthData //基本站月(旬)数据
	{
		BMonthData(Date dateTime, double t)
		{
			m_dateTime = dateTime;
			m_t = t;
		}
		
		Date m_dateTime;
		double m_t; //月(旬)平均气温
	}
	ArrayList<BMonthData> m_alBMonthData = new ArrayList<BMonthData>();
	
	class BDayData //基本站日数据
	{
		BDayData(Date dateTime, double t, double c)
		{
			m_dateTime = dateTime;
			m_t = t;
			m_c = c;
		}
		
		Date m_dateTime;
		double m_t; //日平均气温
		double m_c; //日平均总云量
	}
	ArrayList<BDayData> m_alBDayData = new ArrayList<BDayData>();
	
	class ADayData //考察站日数据
	{
		ADayData(Date dateTime, double t)
		{
			m_dateTime = dateTime;
			m_t = t;
		}
		
		Date m_dateTime;
		double m_t; //日平均气温
	}
	ArrayList<ADayData> m_alADayData = new ArrayList<ADayData>();
	//---------------------------------------------------------------------------
	LinkedList<String> m_llOutput = new LinkedList<String>();
	
}
